Repository navigation
Spec: derived parameters, computed values in action-time effects, bounds on an action's own parameter (#251, #252) - #262
Merged
Conversation
An entry with only min and/or max bounds the action's own parameter (or one another effect adds) instead of declaring it. Every bound must hold; out-of-range names that parameter, with boundBy. describeAction lists them as addedBounds. A bound on a name nothing declares is invalid-added-param (reason undeclared). Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com>
…251) A parameter may declare a formula instead of being given: worked out as the action starts, after the given ones and before bounds, in declaration order, reading only earlier derived ones (a later one is unknown-name at load). Giving one is the new error invalid-param; describeAction marks it derived. Effects that act as an action runs (rolls, choice and changes steps, listed actions, incoming changes) read their content's computed values as self.<name>, as its actions do. Field effects still can't: computed values are worked out after every field. Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com>
…y with only addedBy (#252) Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com>
…one effect's later one (#251) Also: participants' errors come before any parameter's (documented), and the checker restores the aura flag it sets. Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com>
mpigsley
force-pushed
the
spec/computed-in-effects
branch
from
November 2, 2026 17:40
c21c684 to
e181acc
Compare
This was referenced Nov 2, 2026
Closed
mpigsley
added a commit
that referenced
this pull request
Nov 2, 2026
… (#266) * Website: name the LicenseRef- licenses in the home packs table Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: other characters: a runnable aura sample, appliers on every call, keep the observer's file Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: showing text: added parameters, situational choices, aura names, step text, parameter errors Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: changing characters: every change type, naming reactions, held-copy costs don't clamp Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: storing characters: appliedBy, aura and pick entry; caches depend on links and appliers Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: showing a sheet: auras, observes, effectsWhen, aura immunity, re-keying rules-level option IDs Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: text and translation: keys for added parameters, computed values, auras, inline options, rules-level choice issues Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: upgrading: changeContentType, grantsToCopies, grant-not-copied, removed parameters and situational choices Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: rolling dice: derived parameters never passed, unlisted param bounds, replay needs the same release, item tags Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: building characters: picked-copy-invalid, rules-level choice issue IDs Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: implementing, quick start, index: level 6 scope, describeAction, the engine's dependencies Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Guides: packs and rulesets: LicenseRef- packs carry a permission notice Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> * Glossary: activation, added parameter, shared action; update effect operation, handoff, interface and shape change, proposed change Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com> --------- Signed-off-by: Mitchel Pigsley <mpigsley@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two spec gaps from the round-2 pack adoptions (#249, #250). One commit per issue.
Closes #252: a
paramseffect bounds a parameter the action already declaresTook the recommended option.
Design. A
paramseffect's entry that names a parameter the run already has, with onlyminand/ormax(notype), adds bounds to that parameter instead of declaring it.params, as an added parameter's bounds do. They are checked with the parameter's own, after them, and every one must hold.out-of-rangenames that parameter. Itsmin/maxare the failing bound's, and the newboundByfield is the content that added it.addedBounds({ addedBy, min?, max? }). A bound that readsparamsis left out, as forminandmax.typestays a declaration (invalid-added-param, reasondeclared). A bound on a name that no action declares and no effect adds isinvalid-added-paramwith the new reasonundeclared, to catch typos. A bound on a parameter a given run doesn't have is ignored.Why. This is the smallest change that puts the overspend error on
spend. It needs no new op or error shape.Closes #251: derived parameters, and computed values in action-time effects
Took the recommended option (1, derived parameters) and the computed-value read from option 2, which the issue calls independent and small.
Derived parameters. An action's parameter, or one a
paramseffect adds, may declareformulainstead of being given (integer,decimal,booleanorstring; nodefaultoroptional).participants, plusparamsholding the given parameters and the derived ones declared before it.paramseffect, reading a later derived parameter, or itself, isunknown-nameat load. Another effect's derived parameter that comes later is simply absent when the formula runs.params.<name>, everywhereparamsis read, bounds included.use, anactionstep or a handoff is the new runtime errorinvalid-param(reasonderived). The build also reports ause's, a creation start's, a field roll's, anactionstep's and anactioneffect's.derived: trueandrequired: false. Its label is optional.formulaon an item field or a state key is a build error.Deviation: derived parameters read
participants. To allow that, startAction now checks participants before parameters, so participant errors (invalid-participants,duplicate-id,invalid-link-value) are reported ahead of parameter errors. The issue suggestedparticipantin aneachstep. That doesn't fit a value computed once per run, and since #256 the Trip check in the pack readsparticipants.target[0]anyway. Withparticipants, the whole Cunning Strike cost, the Trip size exception included, becomes one parameter.Computed values in effects. An effect that acts as an action runs reads its content's computed values as
self.<name>, as the content's actions already do. That covers effects on rolls, choice steps, changes steps (changesandaction), listed actions (params, with its bounds and derived parameters) and incoming changes. It covers theirwhen, value andthen, and the content's choices' and inline options' effects of those kinds.when. Computed values read every field, so a computed value feeding a field could loop. At load, reading one there isunknown-name, with a message that says why. Applied effects and auras' effects can't read them either, because theirselfis an applied entry. Field formulas, constraints and activation conditions (includingeffectsWhen) stay as they were.selfreads. For an inline option, that is the content it was picked under.Sheet.effectRoots()merges those values at the sites that run while an action runs: roll candidates, option,changesandactioneffects, added params, and incoming effects (one line in changes.ts).Tests
added-params.test.ts(bounds: load, runtime data, describe),derived-params.test.ts(order, bounds,invalid-paramfrom the app and from an action step, type, later-reference load error, added via an effect, participants, describe),computed-in-effects.test.ts(roll, changes, params bounds, granted content's own computed values; field and applied effects rejected).actions/added-params-bound-own,actions/added-params-bound-own-describe,loads/added-params-bound-undeclared,actions/derived-param-run(an added derived parameter readingself.<computed>),actions/derived-param-given,actions/derived-param-describe,loads/derived-param-reads-later,loads/computed-in-field-effect. Two test features were added totest-action-params(grace,overload).useand anactionstep giving a derived parameter, and aformulaon a state key. Engine: oneparamseffect's derived parameter reading a later one fails to load.App-facing changes
derived: true(don't ask for it) andaddedBounds.invalid-param(reasonderived).out-of-rangemay carryboundBy.invalid-added-paramhas a new reason,undeclared.invalid-participantsnow comes before parameter errors.pnpm types), spec docs, guides (rolling-dice.md) and glossary are updated. No saved shape changes. Changesets: spec and engine, minor.Pack follow-up
Not changed in this PR.
packs/5e/srd-5.2/rules/class-rogue.yaml,packs/5e/srd-5.2/content/features/rogue/cunning-strike.yaml): declare one derived parameter,cunningStrikeCost, in the feature's firstparamseffect. It readscunningStrikeandcunningStrike2(behindhas()),rogue.strikeEffects, the Trip check on the target's size (guarded as the pack does now:has(participants.target) && size(participants.target) > 0 && has(participants.target[0].creature.size) && ...; like the current rules effect, it assumes a single target, since a derived parameter is one value per run), and whether the pair fits inrogue.sneakAttack. The rules'sneakAttackeffect (its value andwhen) and the two strikeactioneffects (theirwhen) then readparams.cunningStrikeCost, replacing the four copies of the cost expression. The DC becomes a plain computed value (strikeDc: 8 + abilities.dex.mod + proficiency.bonus) that the strike effects read asself.strikeDc, so therogue.strikeDcfield, itsseteffect and itsdisplayentry can go. Update the README's Cunning Strike notes (packs/5e/srd-5.2/README.md, around lines 163-169 and 305) to match.packs/draw-steel/heroes/content/abilities/conduit/healing-grace.yaml): replace themaxongraceRecoverieswithspend: { min: 'params.graceRecoveries + (params.graceStand ? 1 : 0) + (params.graceEnd ? 1 : 0)' }, so an overspend namesspend. Update the README line that says the overspend is reported ongraceRecoveries(packs/draw-steel/heroes/README.md, around lines 99-101).computedentries that read a field (cwn-srddrones,draw-steel-heroespotency, theorcspell DCs) read genuinely shared fields, and 5e monk DCs are shared by several features.